package pl.edu.agh.jemo.evolution.objfunc;

import pl.edu.agh.jemo.evolution.specimen.Specimen;

/**
 * Class representing typical mathematical optimalization problem.
 * ClassicObjectiveFunction is implementation of ObjectiveFunction interface dedicated for typical optimization problems.
 * It should be generally used for multidimensional functions with unknown extremas.
 * It is assumed that functions are maximization problems. For minimalization problems it is recommended to multiply returned value by -1.
 * 
 * @author Marcin Zbijowski
 */
public abstract class ClassicObjectiveFunction implements ObjectiveFunction {

	/**
	 * Holds domain definition for each dimension.
	 * Domain is assumed to be conntinous.
	 * First dimension of array refers to function dimension index.
	 * For each dimension two values are stored, lower (0) and upper (1) bound of domain, for specified dimension.
	 */
	protected Double[][] boundaries;	// Dev: noncontinous boundaries?
	
	/**
	 * Number of dimensions of specimen required for function to be able to calculate it's value. 
	 */
	protected int dimensions;
	
	/**
	 * String formula in gnuplot readable format, used for genotype plotting.
	 */
	protected String formula;
	
	/**
	 * Test if given specimen lies in objective functino domain.
	 * Method compares specimen genotype, with function boundaries.
	 * If specimen genotype is shorter than function dimensions, false is returned without further check.
	 * However specimen with genotypes longer than required are accepted. Surplus dimensions are skipped while testing.
	 * 
	 * @param specimen Queried specimen reference. It is assumed that specimen genotype array has been initialized.
	 * @return True if given specimen belongs to function domain, flase otherwise 
	 */
	public boolean isInDomain(Specimen specimen) {
		if (specimen.getGenotype().length < dimensions) {
			return false;
		}
		for (int i = 0; i < dimensions; i++) {
			if (!((specimen.getGenotype()[i].asDouble() >= boundaries[i][0]) && (specimen.getGenotype()[i].asDouble() < boundaries[i][1])))
				return false;
		}
		return true;
	}

	/**
	 * Returns two dimensional array of domain boundaries.
	 * First dimension of array refers to function dimension index.
	 * For each dimension two values are stored, lower (0) and upper (1) bound of domain, for specified dimension.
	 *
	 * @return Two dimensional array of boundaries.
	 */
	public Double[][] getBoundaries() {
		return boundaries;
	}

	/**
	 * Returns dimensions of specimen genotype needed to compute function value.
	 * 
	 * @return number of dimensions of function
	 */
	public int getDimensions() {
		return dimensions;
	}

	/**
	 * Returns String formula in gnuplot readable format.
	 * Formula is used for genotype plotting.
	 * 
	 * @return String containing function formula
	 */
	public String getFormula() {
		return formula;
	}

}
